/*
 * @Description:
 * @Author: liyuhao
 * @Date: 2021-06-30 17:46:11
 * @LastEditors: Please set LastEditors
 * @LastEditTime: 2023-06-27 09:57:27
 */
import React, { useCallback, useRef, useState } from 'react'

export interface Keys {
    selecteKeys: React.Key[] // 所有的选择项 包括子项和夫项 子项被选择时父项也要呈现选中状态
    realKeys: (React.Key | undefined)[] // 真正的选择项
    focusedIndex?: number
    videoCount: number
}

export interface TracingTreeItem {
    fathers: React.Key[] | []
    data: any
}

// 溯源树 以最后一级的key为键 值为包含它所有父级的数组
export interface TracingTree {
    [key: string]: TracingTreeItem

    [key: number]: TracingTreeItem
}

const getSelectedKeys = (
    keys: (React.Key | undefined)[],
    tracingTree: TracingTree,
) => {
    // const realKeys = keys.filter(v => !(v || v === 0) || !!tracingTree[v])
    const _keys = keys.filter((v) => v || v === 0) as React.Key[]
    const _fatherKeys = []
    for (const key of keys) {
        if (key || key === 0) {
            // @ts-ignore
            tracingTree[key] && _fatherKeys.push(...tracingTree[key].fathers)
        }
    }
    return {
        realKeys: keys,
        selecteKeys: [...new Set([..._keys, ..._fatherKeys])],
    }
}

const getEmptyIndex = (keys: (React.Key | undefined)[], max: number) => {
    const _keys = keys?.slice(0, max)
    return _keys && _keys.length > 0 && _keys.indexOf(undefined) > 0
        ? _keys.indexOf(undefined)
        : 0
}

const defaultMax = 6
const defaultVideoCount = 4

const useMonitorTree = (defaultKeys: (React.Key | undefined)[]) => {
    const [keyState, setKeys] = useState<Keys>(() => {
        const realKeys = defaultKeys || Array(defaultMax).fill(undefined)
        const selecteKeys = realKeys.filter((v) => v || v === 0) as React.Key[]
        return {
            selecteKeys,
            realKeys,
            focusedIndex: undefined,
            videoCount: defaultVideoCount,
        }
    })

    const initDefaultKeys = (tracingTree: TracingTree) => {
        const defaultKeys: any = [];
        for (const key in tracingTree) {
            defaultKeys.push(key);
        }
        setKeys((v) => ({
            ...v,
            realKeys: defaultKeys.slice(0, keyState.videoCount),
        }));
        tracingTreeCache.current = tracingTree;
    };

    const tracingTreeCache = useRef<TracingTree>({})
    const nextIndex = useRef<number>(
        getEmptyIndex(defaultKeys, defaultVideoCount),
    ) // 下次选择操作时视频的填入位置

    // 全量更新 若多棵树需共享选中状态 需保证树之间的key不重复 将它们的溯源树合并传入即可实现
    const select = useCallback(
        (key: React.Key, tracingTree: TracingTree) => {
            tracingTreeCache.current = tracingTree
            const isFocused = keyState.focusedIndex || keyState.focusedIndex === 0
            // const childKeys = keys.filter(v => !!tracingTree[v])
            const _keys = [...keyState.realKeys]
            if (isFocused) {
                const _keyIndex = _keys.indexOf(key)
                _keys[keyState.focusedIndex as number] = key
                if (_keyIndex > 0) {
                    _keys[_keyIndex] = undefined
                    setKeys((v) => ({
                        ...v,
                        realKeys: _keys,
                    }))
                } else {
                    setKeys((v) => ({
                        ...v,
                        ...getSelectedKeys(_keys, tracingTree),
                    }))
                }
            } else {
                _keys[nextIndex.current] = key
                const emptyIndex = getEmptyIndex(_keys, keyState.videoCount)
                nextIndex.current =
                    nextIndex.current === keyState.videoCount - 1
                        ? 0
                        : emptyIndex > 0
                            ? emptyIndex
                            : nextIndex.current + 1
                setKeys((v) => ({
                    ...v,
                    ...getSelectedKeys(_keys, tracingTree),
                }))
            }
        },
        [keyState],
    )

    const focus = useCallback(
        (focusedIndex?: number) => {
            setKeys((v) => ({
                ...v,
                focusedIndex:
                    (v.focusedIndex || v.focusedIndex === 0) &&
                        focusedIndex === v.focusedIndex
                        ? undefined
                        : focusedIndex,
            }))
            if (!(focusedIndex || focusedIndex === 0)) {
                nextIndex.current = getEmptyIndex(
                    keyState.realKeys,
                    keyState.videoCount,
                )
            }
        },
        [keyState],
    )

    const clear = useCallback(
        (key: React.Key | undefined) => {
            if (
                (keyState.focusedIndex || keyState.focusedIndex === 0) &&
                keyState.focusedIndex === key
            ) {
                select(key, tracingTreeCache.current)
            } else {
                // 暂时不考虑tracingTree的变化 只根据keys变化更新
                const _keys = [...keyState.realKeys]
                const deleteIndex = _keys.indexOf(key)
                if (deleteIndex > -1) {
                    _keys[deleteIndex] = undefined
                    // select(_keys, tracingTreeCache.current)
                    const _newKeys = getSelectedKeys(_keys, tracingTreeCache.current)
                    setKeys((v) => ({
                        ...v,
                        ..._newKeys,
                    }))
                    nextIndex.current = getEmptyIndex(
                        _newKeys.realKeys,
                        keyState.videoCount,
                    )
                }
            }
        },
        [keyState, select],
    )

    const clearAll = useCallback(() => {
        setKeys((v) => ({ ...v, selecteKeys: [], realKeys: [] }))
        nextIndex.current = 0
    }, [keyState])

    const setMax = useCallback(
        (value: number) => {
            if (value > defaultMax) {
                return
            }
            if (value < keyState.videoCount) {
                // 缩小时删除多余数据
                const _keys = keyState.realKeys.map((v, index) => {
                    return index < value ? v : undefined
                })
                const _newKeys = getSelectedKeys(_keys, tracingTreeCache.current)
                setKeys((v) => ({
                    ...v,
                    ..._newKeys,
                    videoCount: value,
                    focusedIndex:
                        (v.focusedIndex || v.focusedIndex === 0) && v.focusedIndex < value
                            ? v.focusedIndex
                            : undefined,
                }))
                nextIndex.current =
                    nextIndex.current < value
                        ? nextIndex.current
                        : getEmptyIndex(_newKeys.realKeys, value)
            } else {
                setKeys((v) => ({
                    ...v,
                    videoCount: value,
                }))
                nextIndex.current =
                    keyState.focusedIndex || keyState.focusedIndex === 0
                        ? keyState.focusedIndex
                        : getEmptyIndex(keyState.realKeys, value)
            }
        },
        [keyState],
    )

    return {
        keyState,
        tracingTree: tracingTreeCache,
        initDefaultKeys,
        setKeys,
        select,
        clear,
        focus,
        clearAll,
        setMax,
    }
}

export default useMonitorTree
